package com.abc.robot01.activity

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.DragInteraction
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.lerp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp


@Stable
object MySliderDefaults {

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun Track(
        rangeSliderState: MyRangeSliderState,
        modifier: Modifier = Modifier,
        colors: MySliderColors,
        enabled: Boolean = true
    ) {
        Track(
            rangeSliderState,
            modifier,
            enabled,
            colors,
            thumbTrackGapSize = ThumbTrackGapSize,
            trackInsideCornerSize = TrackInsideCornerSize
        )
    }

    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun Track(
        sliderState: MySliderState,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
        colors: MySliderColors,
        drawStopIndicator: (DrawScope.(Offset) -> Unit)? = {
            MySliderDefaults.drawStopIndicator(
                drawScope = this,
                offset = it,
                color = colors.trackColor(enabled, active = true),
                size = MySliderDefaults.TrackStopIndicatorSize
            )
        },
        drawTick: DrawScope.(Offset, Color) -> Unit = { offset, color ->
            MySliderDefaults.drawStopIndicator(
                drawScope = this,
                offset = offset,
                color = color,
                size = MySliderDefaults.TickSize
            )
        },
        thumbTrackGapSize: Dp = ThumbTrackGapSize,
        trackInsideCornerSize: Dp = TrackInsideCornerSize
    ) {
        val inactiveTrackColor = colors.trackColor(enabled, active = false)
        val activeTrackColor = colors.trackColor(enabled, active = true)
        val inactiveTickColor = colors.tickColor(enabled, active = false)
        val activeTickColor = colors.tickColor(enabled, active = true)
        Canvas(
            modifier
                .fillMaxWidth()
                .height(TrackHeight)
                .rotate(if (LocalLayoutDirection.current == LayoutDirection.Rtl) 180f else 0f)
        ) {
            drawTrack(
                sliderState.tickFractions,
                0f,
                sliderState.coercedValueAsFraction,
                inactiveTrackColor,
                activeTrackColor,
                inactiveTickColor,
                activeTickColor,
                sliderState.trackHeight.toDp(),
                0.toDp(),
                sliderState.thumbWidth.toDp(),
                thumbTrackGapSize,
                trackInsideCornerSize,
                drawStopIndicator,
                drawTick,
                isRangeSlider = false
            )
        }
    }

    @Composable
    fun Track(
        rangeSliderState: MyRangeSliderState,
        modifier: Modifier = Modifier,
        enabled: Boolean = true,
        colors: MySliderColors,
        drawStopIndicator: (DrawScope.(Offset) -> Unit)? = {
            MySliderDefaults.drawStopIndicator(
                drawScope = this,
                offset = it,
                color = colors.trackColor(enabled, active = true),
                size = TrackStopIndicatorSize
            )
        },
        drawTick: DrawScope.(Offset, Color) -> Unit = { offset, color ->
            MySliderDefaults.drawStopIndicator(
                drawScope = this,
                offset = offset,
                color = color,
                size = TickSize
            )
        },
        thumbTrackGapSize: Dp = ThumbTrackGapSize,
        trackInsideCornerSize: Dp = TrackInsideCornerSize
    ) {
        val inactiveTrackColor = colors.trackColor(enabled, active = false)
        val activeTrackColor = colors.trackColor(enabled, active = true)
        val inactiveTickColor = colors.tickColor(enabled, active = false)
        val activeTickColor = colors.tickColor(enabled, active = true)
        Canvas(
            modifier
                .fillMaxWidth()
                .height(TrackHeight)
                .rotate(if (LocalLayoutDirection.current == LayoutDirection.Rtl) 180f else 0f)
        ) {
            drawTrack(
                rangeSliderState.tickFractions,
                rangeSliderState.coercedActiveRangeStartAsFraction,
                rangeSliderState.coercedActiveRangeEndAsFraction,
                inactiveTrackColor,
                activeTrackColor,
                inactiveTickColor,
                activeTickColor,
                rangeSliderState.trackHeight.toDp(),
                rangeSliderState.startThumbWidth.toDp(),
                rangeSliderState.endThumbWidth.toDp(),
                thumbTrackGapSize,
                trackInsideCornerSize,
                drawStopIndicator,
                drawTick,
                isRangeSlider = true,
            )
        }
    }

    private fun DrawScope.drawTrack(
        tickFractions: FloatArray,
        activeRangeStart: Float,
        activeRangeEnd: Float,
        inactiveTrackColor: Color,
        activeTrackColor: Color,
        inactiveTickColor: Color,
        activeTickColor: Color,
        height: Dp,
        startThumbWidth: Dp,
        endThumbWidth: Dp,
        thumbTrackGapSize: Dp,
        trackInsideCornerSize: Dp,
        drawStopIndicator: (DrawScope.(Offset) -> Unit)?,
        drawTick: DrawScope.(Offset, Color) -> Unit,
        isRangeSlider: Boolean
    ) {
        val sliderStart = Offset(0f, center.y)
        val sliderEnd = Offset(size.width, center.y)
        val trackStrokeWidth = height.toPx()

        val sliderValueEnd =
            Offset(sliderStart.x + (sliderEnd.x - sliderStart.x) * activeRangeEnd, center.y)

        val sliderValueStart =
            Offset(sliderStart.x + (sliderEnd.x - sliderStart.x) * activeRangeStart, center.y)

        val cornerSize = trackStrokeWidth / 2
        val insideCornerSize = trackInsideCornerSize.toPx()
        var startGap = 0f
        var endGap = 0f
        if (thumbTrackGapSize > 0.dp) {
            startGap = startThumbWidth.toPx() / 2 + thumbTrackGapSize.toPx()
            endGap = endThumbWidth.toPx() / 2 + thumbTrackGapSize.toPx()
        }

        // inactive track (range slider)
        if (isRangeSlider && sliderValueStart.x > sliderStart.x + startGap + cornerSize) {
            val start = sliderStart.x
            val end = sliderValueStart.x
            drawTrackPath(
                Offset.Zero,
                Size(end - start, trackStrokeWidth),
                inactiveTrackColor,
                cornerSize,
                insideCornerSize
            )
            drawStopIndicator?.invoke(this, Offset(start + cornerSize, center.y))
        }
        // inactive track
        if (sliderValueEnd.x < sliderEnd.x - endGap - cornerSize) {
            val start = sliderValueEnd.x
            val end = sliderEnd.x
            drawTrackPath(
                Offset(start, 0f),
                Size(end - start, trackStrokeWidth),
                inactiveTrackColor,
                insideCornerSize,
                cornerSize
            )
            drawStopIndicator?.invoke(this, Offset(end - cornerSize, center.y))
        }
        // active track
        val activeTrackStart = if (isRangeSlider) sliderValueStart.x else 0f
        val activeTrackEnd = sliderValueEnd.x
        val startCornerRadius = if (isRangeSlider) insideCornerSize else cornerSize
        if (activeTrackEnd - activeTrackStart > startCornerRadius) {
            drawTrackPath(
                Offset(activeTrackStart, 0f),
                Size(activeTrackEnd - activeTrackStart, trackStrokeWidth),
                activeTrackColor,
                startCornerRadius,
                insideCornerSize
            )
        }

        val start = Offset(sliderStart.x + cornerSize, sliderStart.y)
        val end = Offset(sliderEnd.x - cornerSize, sliderEnd.y)
        val tickStartGap = sliderValueStart.x - startGap..sliderValueStart.x + startGap
        val tickEndGap = sliderValueEnd.x - endGap..sliderValueEnd.x + endGap
        tickFractions.forEachIndexed { index, tick ->
            // skip ticks that fall on the stop indicator
            if (drawStopIndicator != null) {
                if ((isRangeSlider && index == 0) || index == tickFractions.size - 1) {
                    return@forEachIndexed
                }
            }

            val outsideFraction = tick > activeRangeEnd || tick < activeRangeStart
            val center = Offset(lerp(start, end, tick).x, center.y)
            // skip ticks that fall on a gap
            if ((isRangeSlider && center.x in tickStartGap) || center.x in tickEndGap) {
                return@forEachIndexed
            }
            drawTick(
                this,
                center, // offset
                if (outsideFraction) inactiveTickColor else activeTickColor // color
            )
        }
    }

    private fun DrawScope.drawTrackPath(
        offset: Offset,
        size: Size,
        color: Color,
        startCornerRadius: Float,
        endCornerRadius: Float
    ) {
        val startCorner = CornerRadius(startCornerRadius, startCornerRadius)
        val endCorner = CornerRadius(endCornerRadius, endCornerRadius)
        val track =
            RoundRect(
                rect = Rect(Offset(offset.x, 0f), size = Size(size.width, size.height)),
                topLeft = startCorner,
                topRight = endCorner,
                bottomRight = endCorner,
                bottomLeft = startCorner
            )
        trackPath.addRoundRect(track)
        drawPath(trackPath, color)
        trackPath.rewind()
    }

    private fun drawStopIndicator(drawScope: DrawScope, offset: Offset, size: Dp, color: Color) {
        with(drawScope) { drawCircle(color = color, center = offset, radius = size.toPx() / 2f) }
    }

    /** The default size for the stop indicator at the end of the track. */
    val TrackStopIndicatorSize: Dp = SliderTokens.StopIndicatorSize

    /** The default size for the ticks if steps are greater than 0. */
    val TickSize: Dp = SliderTokens.StopIndicatorSize

    private val trackPath = Path()




    @Composable
    fun Thumb(
        interactionSource: MutableInteractionSource,
        modifier: Modifier = Modifier,
        colors: MySliderColors,
        enabled: Boolean = true,
        thumbSize: DpSize = ThumbSize
    ) {
        val interactions = remember { mutableStateListOf<Interaction>() }
        LaunchedEffect(interactionSource) {
            interactionSource.interactions.collect { interaction ->
                when (interaction) {
                    is PressInteraction.Press -> interactions.add(interaction)
                    is PressInteraction.Release -> interactions.remove(interaction.press)
                    is PressInteraction.Cancel -> interactions.remove(interaction.press)
                    is DragInteraction.Start -> interactions.add(interaction)
                    is DragInteraction.Stop -> interactions.remove(interaction.start)
                    is DragInteraction.Cancel -> interactions.remove(interaction.start)
                }
            }
        }

        val size =
            if (interactions.isNotEmpty()) {
                thumbSize.copy(width = thumbSize.width / 2)
            } else {
                thumbSize
            }
        Spacer(
            modifier
                .size(size)
                .hoverable(interactionSource = interactionSource)
                .background(colors.thumbColor(enabled), SliderTokens.HandleShape)
        )
    }

}

